package com.fwj.authorization.security;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import com.fwj.authorization.security.constants.CommonConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.*;

/**
 * @author fwj
 * @date 2025/03/18
 */
@Slf4j
@UtilityClass
public class JwtTokenUtil implements Serializable {

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    public static String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + 2592000L * 1000);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, CommonConstants.SECRET)
                .compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public static LoginUser getUserFromToken(String token) {
        LoginUser loginUser = null;
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(CommonConstants.SECRET)
                    .parseClaimsJws(token)
                    .getBody();
            Long userId = claims.get("id", Long.class);
            Long orgId = claims.get("orgId", Long.class);
            String tenantId = claims.get("tenantId", String.class);
            String username = claims.get("username", String.class);
            String realname = claims.get("realname", String.class);
            String password = claims.get("password", String.class);
            String type = claims.get("type", String.class);
            Boolean enabled = claims.get("enabled", Boolean.class);
            List<String> rolePrem = claims.get("rolePrem", List.class);
            List<LinkedHashMap<String, Object>> authorities = (List<LinkedHashMap<String, Object>>) claims.get("authorities");
            List<SimpleGrantedAuthority> userGrantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
            for (LinkedHashMap<String, Object> map : authorities) {
                userGrantedAuthorities.add(new SimpleGrantedAuthority(MapUtil.getStr(map, "authority")));
            }
            Boolean accountNonExpired = claims.get("accountNonExpired", Boolean.class);
            return new LoginUser(userId, orgId, tenantId,
                    username, realname, password,
                    enabled, true, true,
                    accountNonExpired, userGrantedAuthorities, type, rolePrem);
        } catch (Exception e) {
            log.error("JwtTokenUtil.getClaimsFromToken error", e);
        }
        return loginUser;
    }

    /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(CommonConstants.SECRET)
                    .parseClaimsJws(token)
                    .getBody();
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public static String refreshToken(String token) {
        String refreshedToken = null;
        try {
            Object body = Jwts.parser()
                    .setSigningKey(CommonConstants.SECRET)
                    .parseClaimsJws(token)
                    .getBody();
            LoginUser user = (LoginUser) body;
            Map<String, Object> map = BeanUtil.beanToMap(user);
            refreshedToken = generateToken(map);
        } catch (Exception e) {
            log.error("JwtTokenUtil.refreshToken error", e);
        }
        return refreshedToken;
    }

    /**
     * 验证令牌
     *
     * @param token       令牌
     * @param userDetails 用户
     * @return 是否有效
     */
    public static Boolean validateToken(String token, UserDetails userDetails) {
        //JwtUser user = (JwtUser) userDetails;
        //String username = getUsernameFromToken(token);
        //return (username.equals(user.getUsername()) && !isTokenExpired(token));
        return false;
    }

    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 获取用户
     *
     * @param authentication Authentication
     * @return LoginUser
     * <p>
     * 获取当前用户的全部信息 EnablePdcResourceServer true
     * 获取当前用户的用户名 EnablePdcResourceServer false
     */
    public LoginUser getUser(Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if (principal instanceof LoginUser) {
            return (LoginUser) principal;
        }
        return null;
    }

    /**
     * 获取用户
     */
    public LoginUser getUser() {
        Authentication authentication = getAuthentication();
        if (null == authentication) {
            return null;
        }
        return getUser(authentication);
    }

}
